<?php

namespace app\common\service;

use app\common\logic\SystemConfigLogic;
use app\common\utils\Arr;
use support\Cache;

class SignService {
    protected static $tll = 120;
    /**
     * 生成签名
     * @param array $params  业务参数
     * @param int    $ts     时间戳
     * @param string $nonce  随机串
     * @return string        32 位小写 md5
     */
    public static function sign(array $params, int $ts, string $nonce): string
    {
        $logic = new SystemConfigLogic();
        $uploadConfig = $logic->getGroup('oa_config');
        $secret = Arr::getConfigValue($uploadConfig, 'oa_app_secret');
        ksort($params);
        $json = json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        $raw  = strtolower($secret . $json . $secret . $ts . $nonce);
        return md5($raw);
    }

    /**
     * 校验签名
     * @param array $body   请求体, 包含时间戳, 随机串, 业务参数, 签名
     * @return bool
     */
    public static function verify(array $body): bool
    {
        $ts    = $body['timestamp'] ?? 0;
        $nonce = $body['nonce'] ?? '';
        $sign  = $body['sign'] ?? '';
        $data  = $body['data'] ?? [];

        // 时间窗口
        if (abs(time() - $ts) > self::$tll) {
            return false;
        }
        // 重放检查
        $key = 'nonce_' . $nonce;
        if (Cache::get($key)) {
            return false;
        }
        Cache::set($key, 1, self::$tll);
        // 签名校验
        $expect = self::sign($data, $ts, $nonce);
        return hash_equals(strtolower($expect), strtolower($sign));
    }
}